package fr.emse.tatiana.replayable.analysis;

import java.util.HashMap;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;

import fr.emse.tatiana.ApplicationActionBarAdvisor;
import fr.emse.tatiana.display.BadDisplayFile;
import fr.emse.tatiana.display.DisplayFileReader;
import fr.emse.tatiana.replayable.Anchor;
import fr.emse.tatiana.replayable.IReplayableModel;
import fr.emse.tatiana.utils.WSFileDialog;

public abstract class AbstractAnalysis implements IAnalysis {

	protected String name;
	protected IFile file;
	protected HashMap<Anchor, Object> values;
	protected boolean saved = false;
	protected IProject project;
	protected javax.swing.event.EventListenerList listenerList = new javax.swing.event.EventListenerList();

	public AbstractAnalysis(String name, IProject p) {
		this.project = p;
		this.name=name;
		this.values = new HashMap<Anchor,Object>();
		saved=true;
		this.doInit();
	}
	
	public AbstractAnalysis(IFile file) throws BadDisplayFile {
		this(file.getName(),file.getProject());
		this.file = file;
		this.parseFile(new DisplayFileReader(file.getLocation().toString()));
	}
	
	protected abstract void parseFile(DisplayFileReader displayFileReader) throws BadDisplayFile;

	protected abstract void doInit();

	public void doSave() {
		if (saveToAnalysisFile(this.file)) {
			fireAnalysisEvent(new AnalysisEvent(this));
		}
	}
	
	/* (non-Javadoc)
	 * @see fr.emse.tatiana.replayable.analysis.IAnalysis#doSave(java.lang.String)
	 */
	public void doSave(String analysisname) {
		IFolder analyses = project.getFolder("analyses");

		try {
			analyses.refreshLocal(IResource.DEPTH_INFINITE, null);
			if (!analyses.exists()) {
				analyses.create(false,true,null);
			}
		} catch (CoreException e) {
			// shouldn't happen
			e.printStackTrace();
		}
		
		IFile file = analyses.getFile(analysisname);
		if (saveToAnalysisFile(file)) {
			if (!file.exists()) {
				try {
					file.refreshLocal(IResource.DEPTH_ZERO, null);
				} catch (CoreException e) {
					// shouldn't happen
					e.printStackTrace();
				}
			}
			this.file = file;
			this.name = file.getName();
			fireAnalysisEvent(new AnalysisEvent(this));
		}
	}
	
	protected abstract boolean saveToAnalysisFile(IFile file2);

	public String getName() {
		return this.name;
	}

	public boolean hasValueForAnchor(Anchor anchor) {
		Object ret = values.get(anchor);
		if (ret != null && !ret.equals(doGetNullValue())) {
			return true;
		}
		return false;
	}

	public Object getValueForAnchor(Anchor anchor) {
		Object ret = values.get(anchor);
		return (ret==null) ? doGetNullValue() : ret;
	}

	public String getTextValueForAnchor(Anchor anchor) {
		Object ret = values.get(anchor);
		return (ret==null) ? "" : doGetStringValue(ret);
	}

	protected Object doGetNullValue() {
		return "";
	}

	protected String doGetStringValue(Object ret) {
		return ret.toString();
	}

	public CellEditor getChooser(Composite parent) {
		return new TextCellEditor(parent, SWT.MULTI);
	}

	public void setValue(Anchor anchor, Object value) {
		if (value==null || value.equals(values.get(anchor))) 
			return;
	
		values.put(anchor, value);
		saved = false;
		fireAnalysisEvent(new AnalysisEvent(this,anchor));	
	}
	
	public void setMultiple(Set<Anchor> anchors, Object value) {
		for (Anchor anchor: anchors) {
			setValue(anchor, value);
		}
	}
	
	public IContributionItem getMenuManager(List sel, IReplayableModel r) {
		final MenuManager ret = new MenuManager(name);
		if (!saved) {
			ret.add(new Action("Save") {
				@Override
				public void run() {
					AbstractAnalysis.this.doSave();
				}

			});
		}
		if (!sel.isEmpty()) {
			MenuManager mm = new MenuManager("Current Selection");
			if (this.populateApplyToSelectionMenuManager(sel, r, mm)) {
				ret.add(mm);
			}
		}
		
		return ret;
	}

	protected boolean populateApplyToSelectionMenuManager(List sel, IReplayableModel r, MenuManager mm) {
		return false;
	}

	public Set<Anchor> getAnchors() {
		return values.keySet();
	}

	public void addAnalysisEventListener(AnalysisEventListener listener) {
		listenerList.add(AnalysisEventListener.class, listener);
	}

	public void removeAnalysisEventListener(AnalysisEventListener listener) {
		listenerList.remove(AnalysisEventListener.class, listener);
	}

	protected void fireAnalysisEvent(AnalysisEvent evt) {
		Object[] listeners = listenerList.getListenerList();
		// Each listener occupies two elements - the first is the listener class
		// and the second is the listener instance
		for (int i=0; i<listeners.length; i+=2) {
			if (listeners[i]==AnalysisEventListener.class) {
				((AnalysisEventListener)listeners[i+1]).analysisEventOccurred(evt);
			}
		}
	}

	public boolean isSaved() {
		return saved;
	}

	public boolean hasAnalysisFile() {
		return file!=null;
	}

	public Color getBackground(Anchor anchor) {
		return doGetBackGround(getValueForAnchor(anchor));
	}

	protected Color doGetBackGround(Object valueForAnchor) {
		return ColorConstants.white;
	}

	/* (non-Javadoc)
	 * @see fr.emse.tatiana.replayable.analysis.IAnalysis#getWidth(int)
	 */
	public int getWidth(int col) {
		return 300;
	}

}